package com.longsichao.lscframe.tools;

import android.content.Context;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Locale;

/**
 * @author SONG GUANYULONGSICHAO (leo.song[at]outlook[dot]com)
 * @version 2
 */
public final class LSCLog {
	private static Context context = null;
	private static String fileName;
	private static int lineNumber;
	private static boolean logCat = false;
	private static final String LOGCAT_FORMAT = "%1$s\n%2$s";
	private static boolean logFile = false;
	private static final String LOGFILE_CONTENT_FORMAT = "%1$tF %1$tT\t%2$s\t%3$s\n%4$s\n%5$s";
	private static String methodName;

	public static void d(String msg) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.DEBUG, fileName, createLog(msg), null);
		toLogFile(Log.DEBUG, fileName, createLog(msg), null);
	}

	public static void d(String msg, Throwable t) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.DEBUG, fileName, createLog(msg), t);
		toLogFile(Log.DEBUG, fileName, createLog(msg), t);
	}

	public static void e(String msg) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.ERROR, fileName, createLog(msg), null);
		toLogFile(Log.ERROR, fileName, createLog(msg), null);
	}

	public static void e(String msg, Throwable t) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.ERROR, fileName, createLog(msg), t);
		toLogFile(Log.ERROR, fileName, createLog(msg), t);
	}

	public static void i(String msg) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.INFO, fileName, createLog(msg), null);
		toLogFile(Log.INFO, fileName, createLog(msg), null);
	}

	public static void i(String msg, Throwable t) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.INFO, fileName, createLog(msg), t);
		toLogFile(Log.INFO, fileName, createLog(msg), t);
	}

	public static void logCat(boolean isShow) {
		logCat = isShow;
	}

	public static void logFile(Context applicationContext, boolean isWrite) {
		logFile = isWrite;
		context = applicationContext;
	}

	public static void v(String msg) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.VERBOSE, fileName, createLog(msg), null);
		toLogFile(Log.VERBOSE, fileName, createLog(msg), null);
	}

	public static void v(String msg, Throwable t) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.VERBOSE, fileName, createLog(msg), t);
		toLogFile(Log.VERBOSE, fileName, createLog(msg), t);
	}

	public static void w(String msg) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.WARN, fileName, createLog(msg), null);
		toLogFile(Log.WARN, fileName, createLog(msg), null);
	}

	public static void w(String msg, Throwable t) {
		if (!logCat && !logFile) {
			return;
		}
		getCodeLocation(new Throwable().getStackTrace());
		toLogCat(Log.WARN, fileName, createLog(msg), t);
		toLogFile(Log.WARN, fileName, createLog(msg), t);
	}

	private static String createLog(String msg) {
        return "[" + methodName + ":" + lineNumber + "]" + msg;
	}

	private static String formatLogMsg(int priority, String tag, String message, Throwable ex) {
		String logBody;
		if (ex == null) {
			logBody = "";
		} else {
			logBody = Log.getStackTraceString(ex);
		}
		String level = priorityToString(priority);
        return String.format(Locale.CHINA, LOGFILE_CONTENT_FORMAT, System.currentTimeMillis(), level, tag, message, logBody);
	}

	private static void getCodeLocation(StackTraceElement[] elements) {
		fileName = elements[1].getFileName();
		methodName = elements[1].getMethodName();
		lineNumber = elements[1].getLineNumber();
	}

	private static String priorityToString(int priority) {
		switch (priority) {
		case Log.ASSERT:
			return "assert";
		case Log.DEBUG:
			return "debug";
		case Log.ERROR:
			return "error";
		case Log.INFO:
			return "info";
		case Log.VERBOSE:
			return "verbose";
		case Log.WARN:
			return "warn";
		default:
			return "unknown";
		}
	}

	private static void toLogCat(int priority, String tag, String message, Throwable ex) {
		if (!logCat) {
			return;
		}
		String log;
		if (ex == null) {
			log = message;
		} else {
			String logMessage = message == null ? ex.getMessage() : message;
			String logBody = Log.getStackTraceString(ex);
			log = String.format(LOGCAT_FORMAT, logMessage, logBody);
		}
		Log.println(priority, tag, log);
	}

	private static void toLogFile(int priority, String tag, String message, Throwable ex) {
		if (!logFile || context == null) {
			return;
		}
		File logFile = new File(FileManager.getLogFileNamePath(context));
		if (!logFile.exists()) {
			try {
                boolean isOk = logFile.createNewFile();
                if (!isOk) {
                    Log.w("LSCLog.java", "Create log file error in toLogFile method.");
                }
            } catch (IOException e) {
				e.printStackTrace();
			}
		}
		try {
			String text = formatLogMsg(priority, tag, message, ex);
			BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
			buf.append(text);
			buf.newLine();
			buf.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private LSCLog() {
	}
}
